package com.wh1200.mybatis.xmlless

import com.wh1200.mybatis.xmlless.constant.Annotations
import com.wh1200.mybatis.xmlless.model.TableName
import com.wh1200.mybatis.xmlless.util.getAnnotation
import com.wh1200.mybatis.xmlless.util.getAnnotationFieldValue
import com.wh1200.mybatis.xmlless.util.hasAnyAnnotation
import java.lang.reflect.AnnotatedElement
import java.lang.reflect.Field
import java.lang.reflect.Modifier

/**
 *
 * @author 吴昊
 * @date 2023/12/18 12:42
 * @since v4.0.0
 * @version 1.0
 */
object AnnotationSupport {

  val INSERT_IGNORE_ANNOTATIONS = arrayOf(
      Annotations.COUNT,
      Annotations.PROPERTY_MAPPING,
      Annotations.JOIN_OBJECT,
      Annotations.JOIN_TABLE_COLUMN
  )

  val UPDATE_IGNORE_ANNOTATIONS = arrayOf(
      Annotations.COUNT,
      Annotations.PROPERTY_MAPPING,
      Annotations.JOIN_OBJECT,
      Annotations.JOIN_TABLE_COLUMN,
      Annotations.CREATED_DATE,
      Annotations.CREATED_BY,
      Annotations.DELETED_BY
  )

  val TRANSIENT_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.TRANSIENT, Annotations.Javax.TRANSIENT, Annotations.KOTIN_TRANSIENT
  )

  val CUSTOM_COLUMN_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.COLUMN, Annotations.Javax.COLUMN
  )

  val ALL_COLUMN_ANNOTATIONS = listOf(
      Annotations.Jakarta.COLUMN, Annotations.Javax.COLUMN,
      Annotations.Jakarta.JOIN_COLUMN, Annotations.Javax.JOIN_COLUMN
  )

  val TABLE_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.TABLE, Annotations.Javax.TABLE
  )

  val ID_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.ID, Annotations.Javax.ID,
      Annotations.Plus.ID
  )

  val VERSION_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.VERSION,
      Annotations.Javax.VERSION,
      Annotations.Spring.VERSION
  )

  val NOT_EMPTY_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.NOT_EMPTY,
      Annotations.Javax.NOT_EMPTY
  )

  val NOT_BLANK_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.NOT_BLANK, Annotations.Javax.NOT_BLANK
  )

  val NOT_NULL_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.NOT_NULL,
      Annotations.Javax.NOT_NULL
  )

  val GENERATED_VALUE_ANNOTATIONS = arrayOf(
      Annotations.Jakarta.GENERATED_VALUE,
      Annotations.Javax.GENERATED_VALUE
  )


  fun isInsertIgnore(field: AnnotatedElement): Boolean {
    ALL_COLUMN_ANNOTATIONS.forEach {
      val anno = field.getAnnotation(it)
      if (anno != null) {
        return !anno.getAnnotationFieldValue<Boolean>("insertable")
      }
    }
    return false
  }

  fun getNumericScale(field: AnnotatedElement): Int {
    CUSTOM_COLUMN_ANNOTATIONS.forEach {
      val anno = field.getAnnotation(it)
      if (anno != null) {
        return anno.getAnnotationFieldValue("scale")
      }
    }
    return 0
  }

  fun isUpdateIgnore(field: AnnotatedElement): Boolean {
    ALL_COLUMN_ANNOTATIONS.forEach {
      val anno = field.getAnnotation(it)
      if (anno != null) {
        return !anno.getAnnotationFieldValue<Boolean>("updatable")
      }
    }
    return false
  }

  fun isAutoGeneratedKey(field: AnnotatedElement): Boolean {
    GENERATED_VALUE_ANNOTATIONS.forEach {
      val anno = field.getAnnotation(it)
      if (anno != null) {
        return anno.getAnnotationFieldValue<Any>("strategy").toString() == "SEQUENCE"
      }
    }
    return false
  }

  fun isIdField(field: Field): Boolean {
    return field.hasAnyAnnotation(*ID_ANNOTATIONS)
  }

  fun isVersionField(field: Field): Boolean {
    return field.hasAnyAnnotation(*VERSION_ANNOTATIONS)
  }

  fun isAutoGeneratorStrategy(field: Field): Boolean {
    GENERATED_VALUE_ANNOTATIONS.forEach {
      val anno = field.getAnnotation(it)
      if (anno != null) {
        return anno.getAnnotationFieldValue<Any>("strategy").toString() == "AUTO"
      }
    }
    return false
  }

  fun getCustomColumnName(field: Field): String? {
    CUSTOM_COLUMN_ANNOTATIONS.forEach {
      val anno = field.getAnnotation(it)
      if (anno != null) {
        return anno.getAnnotationFieldValue<String>("name")
      }
    }

    return null
  }

  fun isTransient(field: AnnotatedElement): Boolean {
    if (field is Field) {
      return field.hasAnyAnnotation(*TRANSIENT_ANNOTATIONS) || Modifier.isTransient(field.modifiers)
    }
    return field.hasAnyAnnotation(*TRANSIENT_ANNOTATIONS)
  }

  fun hasCustomTableAnnotation(modelClass: Class<*>): Boolean {
    return modelClass.hasAnyAnnotation(*TABLE_ANNOTATIONS)
  }

  fun getCustomTableName(modelClass: Class<*>): TableName? {
    TABLE_ANNOTATIONS.forEach {
      val anno = modelClass.getAnnotation(it)
      if (anno != null) {
        val name = anno.getAnnotationFieldValue<String>("name")
        val schema = anno.getAnnotationFieldValue<String>("schema")
        return TableName(name, "", schema)
      }
    }
    return null
  }

  fun hasGeneratedValueAnnotation(field: Field): Boolean {
    return field.hasAnyAnnotation(*GENERATED_VALUE_ANNOTATIONS)
  }

}
